package com.itcast.spring6.aop.api;

import lombok.extern.slf4j.Slf4j;
import org.aopalliance.aop.Advice;
import org.springframework.aop.AfterReturningAdvice;
import org.springframework.aop.framework.ProxyFactoryBean;
import org.springframework.aop.support.RegexpMethodPointcutAdvisor;
import org.springframework.context.annotation.*;

import java.util.Arrays;

/**
 * @author zhangtian105
 * @date 2023/5/12
 * @apiNote
 */
@Slf4j
@Configuration
@ComponentScans(value = {@ComponentScan(basePackages = "com.itcast.spring6.aop.api")})
public class ApiApplicationTest {
    public static void main(String[] args) {
        // 创建容器
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext() ;
        applicationContext.register(ApiApplicationTest.class);

        // 启动应用上下文
        applicationContext.refresh();

        HelloWorldService helloWorldService = applicationContext.getBean("proxyFactoryBean", HelloWorldService.class);
        helloWorldService.testThis("知识自由") ;

        // 关闭spring应用上下文
        applicationContext.close();
    }

    /**
     * 过滤通知
     * @return
     */
    @Bean(value = "myAfterReturningAdvice2")
    public RegexpMethodPointcutAdvisor regexpMethodPointcutAdvisor() {
        // 过滤的哪个通知 这里测试过滤的是后置通知
        Advice advice = (AfterReturningAdvice) (returnValue, method, args, target) -> {
            String targetName = target.getClass().getName() ;
            String methodName = method.getName() ;
            String params = Arrays.toString(args) ;

            String msg = "【系统日志】：正在调用->"+targetName+"."+methodName+",携带的参数："+params+ ";目标对象所调用的方法的返回值："+returnValue.toString();

            log.info("【After-Returning-2】spring6.MyAfterReturningAdvice.afterReturning: {}", msg);
        };

        // 切中拦截testThis方法
        String[] patterns = new String[] {".*testThis"} ;
        return new RegexpMethodPointcutAdvisor(patterns, advice) ;
    }

    /**
     * 创建ProxyFactoryBean
     * @return
     */
    @Bean(name = "proxyFactoryBean")
    public ProxyFactoryBean proxyFactoryBean(HelloWorldService helloWorldService) {
        // 1、创建ProxyFactoryBean
        ProxyFactoryBean proxyFactoryBean = new ProxyFactoryBean();
        try {
            // 2、设置目标对象的Bean
            //proxyFactoryBean.setTarget(helloWorldService);
            // 代理工厂生产的代理需要实现的接口列表
            //proxyFactoryBean.setProxyInterfaces(new Class[]{HelloWorldService.class});

            // 也可以通过代理实现类
            proxyFactoryBean.setTargetName("helloWorldServiceImpl");
            /**
             * proxyTargetClass
             * true
             * 目标对象实现了接口 – 使用CGLIB代理机制
             * 目标对象没有接口(只有实现类) – 使用CGLIB代理机制
             * false
             * 目标对象实现了接口 – 使用JDK动态代理机制(代理所有实现了的接口)
             * 目标对象没有接口(只有实现类) – 使用CGLIB代理机制
             */
            proxyFactoryBean.setProxyTargetClass(true);

            // 3、代理通知列表
            proxyFactoryBean.setInterceptorNames("myMethodBeforeAdvice", "myMethodInterceptor", /*"myAfterReturningAdvice",*/ "myAfterReturningAdvice2", "myThrowsAdvice");

            proxyFactoryBean.setExposeProxy(true);
        }catch (Exception e) {
            e.printStackTrace();
        }

        return proxyFactoryBean;
    }
}
